#include <jni.h>
#include <string>
#include "log.h"

#include "RtmpHelper.h"

uint32_t start_time;

int RtmpHelper::connect(char *connectUrl) {
    int ret;
    int retryCount = 0;
    do {
        // 初始化全局变量
        live = (Live *) malloc(sizeof(Live));
        // 将对象中的值恢复成初始值
        memset(live, 0, sizeof(Live));
        LOGE("connect live address %p", live);
        // 1.申请内存
        live->rtmp = RTMP_Alloc();
        // 2.初始化
        RTMP_Init(live->rtmp);
        // live->rtmp->Link.timeout = 100;
        // 3.设置连接的url
        LOGE("connect %s", connectUrl);
        if (!(ret = RTMP_SetupURL(live->rtmp, connectUrl))) {
            LOGE("connect status: %d", ret);
            ++retryCount;
            continue;
        }
        // 4.开启输出模式
        RTMP_EnableWrite(live->rtmp);
        LOGE("RTMP_Connect");
        // 5.连接服务器
        if (!(ret = RTMP_Connect(live->rtmp, nullptr))) {
            ++retryCount;
            continue;
        }
        LOGE("RTMP_ConnectStream");

        start_time = RTMP_GetTime();

        // 6.连接流
        if (!(ret = RTMP_ConnectStream(live->rtmp, 0))) {
            ++retryCount;
            LOGE("RTMP_ConnectStream %d", ret);
            continue;
        }
        LOGE("connect success");
        break;
    } while (retryCount < 5);

    // 没有连接成功，释放内存
    if (!ret && live) {
        LOGE("free(live)");
        free(live);
        live = nullptr;
    }
    return ret;
}

void RtmpHelper::sendData(jbyte *buffer, int length, int type) {
    switch (type) {
        case VIDEO_TYPE:
            sendVideoData(buffer, length);
            break;
        default:
            // sendAudioData(buffer, tms, length, type);
            break;
    }
}

/**
 * 发送视频数据包
 * @param buf eg: 传递第一帧 00 00 00 01 67 64 00 28ACB402201E3CBCA41408081B4284D4  0000000168 EE 06 F2 C0
 * @param length
 * @param tms
 */
void RtmpHelper::sendVideoData(const int8_t *buf, int length) {
    // sps
    if (buf[H264_FLAG_LENGTH] == 0x67) {
        // 缓存sps 和pps 到全局遍历 不需要推流
        if (live && (!live->sps_len || !live->pps_len)) {
            LOGE("缓存sps 和 pps");
            setSpsAndPpsByDSP(buf, length, live);
        }
        return;
    }

    // 如果是I帧
    if (buf[H264_FLAG_LENGTH] == 0x65) {
        LOGE("发送关键帧");
        // sps 和 pps 的packet
        RTMPPacket *packet = createSPS_PPSPacket(live->sps, live->pps, live->sps_len, live->pps_len);
        // 发送sps和pps 的packet
        sendPacket(packet);
    }

    LOGE("发送非关键帧");
    // I B P 帧统一处理，因为只有第一个字节的内容不一样，i为0x17 其他为0x27
    RTMPPacket *packet = createVideoPacket(buf, length);
    sendPacket(packet);
}

/**
 * 通过硬解来缓存视频帧的sps和pps的内容和长度
 * @param buf 包含sps和pps的数据
 * @param length 数据长度
 */
void RtmpHelper::setSpsAndPpsByDSP(const int8_t *buf, int length, Live *live) {
    // buf 数据示例
    // 000000016742800ADA022079EF948283030368509A8 00000000168CE06F2
    for (int i = 0; i < length; i++) {
        //0x00 0x00 0x00 0x01
        if (i + H264_FLAG_LENGTH < length) {
            if (buf[i] == 0x00 && buf[i + 1] == 0x00
                && buf[i + 2] == 0x00
                && buf[i + 3] == 0x01) {
                //0x00 0x00 0x00 0x01 7 sps 0x00 0x00 0x00 0x01 8 pps
                //将sps pps分开
                //找到pps
                if (buf[i + 4] == 0x68) {
                    //去掉界定符
                    live->sps_len = i - H264_FLAG_LENGTH;
                    live->sps = static_cast<int8_t *>(malloc(live->sps_len));
                    memcpy(live->sps, buf + H264_FLAG_LENGTH, live->sps_len);
                    live->pps_len = length - (H264_FLAG_LENGTH + live->sps_len) - H264_FLAG_LENGTH;
                    live->pps = static_cast<int8_t *>(malloc(live->pps_len));
                    memcpy(live->pps, buf + H264_FLAG_LENGTH + live->sps_len + H264_FLAG_LENGTH, live->pps_len);
                    LOGE("sps:%d pps:%d", live->sps_len, live->pps_len);
                    break;
                }
            }
        }
    }
}

RTMPPacket *RtmpHelper::createSPS_PPSPacket(int8_t *sps, int8_t *pps, int sps_len, int pps_len) {
    // 构建SPS 和 PPS的数据包
    // sps和pps帧的数据长度，5为协议头的长度，具体见asset/rtmp/RTMP视频包数据.png(sps与pps的数据内容)
    int body_size = 5 + 8 + sps_len + 3 + pps_len;
    RTMPPacket *packet = (RTMPPacket *) malloc(sizeof(RTMPPacket));
    RTMPPacket_Alloc(packet, body_size);
    int i = 0;
    //AVC sequence header 与IDR一样
    packet->m_body[i++] = 0x17;
    //AVC sequence header 设置为0x00
    packet->m_body[i++] = 0x00;
    //CompositionTime
    packet->m_body[i++] = 0x00;
    packet->m_body[i++] = 0x00;
    packet->m_body[i++] = 0x00;
    //AVC sequence header
    packet->m_body[i++] = 0x01;   //configurationVersion 版本号 1
    packet->m_body[i++] = sps[1]; //profile 如baseline、main、 high

    packet->m_body[i++] = sps[2]; //profile_compatibility 兼容性
    packet->m_body[i++] = sps[3]; //profile level
    packet->m_body[i++] = 0xFF; // reserved（111111） + lengthSizeMinusOne（2位 nal 长度） 总是0xff
    //sps
    packet->m_body[i++] = 0xE1; //reserved（111） + lengthSizeMinusOne（5位 sps 个数） 总是0xe1
    //sps length 2字节
    packet->m_body[i++] = (sps_len >> 8) & 0xff; //第0个字节
    packet->m_body[i++] = sps_len & 0xff;        //第1个字节
    memcpy(&packet->m_body[i], sps, sps_len);
    i += live->sps_len;

    /*pps*/
    packet->m_body[i++] = 0x01; //pps number
    //pps length
    packet->m_body[i++] = (pps_len >> 8) & 0xff;
    packet->m_body[i++] = pps_len & 0xff;
    memcpy(&packet->m_body[i], pps, pps_len);
    packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
    packet->m_nBodySize = body_size;
    // 随意分配一个管道（尽量避开rtmp.c中使用的）
    packet->m_nChannel = 0x04;
    //不使用绝对时间
    packet->m_hasAbsTimestamp = 0;
    packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
    packet->m_nInfoField2 = live->rtmp->m_stream_id;
    return packet;
}

RTMPPacket *RtmpHelper::createVideoPacket(const int8_t *buf, int len) {

    LOGE("createVideoPacket");

    // 过滤标志位，拿到真正的帧数据
    buf += H264_FLAG_LENGTH;
    // 总的长度需要减去过滤过的标志为的长度，防止越界
    len -= H264_FLAG_LENGTH;

    // 9为 I B P 帧的协议头的长度
    int body_size = len + 9;

    RTMPPacket *packet = (RTMPPacket *) malloc(sizeof(RTMPPacket));
    RTMPPacket_Alloc(packet, len + 9);

    // B P 帧的第一个字节为0x27
    packet->m_body[0] = 0x27;

    if (buf[0] == 0x65) { //关键帧为0x17
        packet->m_body[0] = 0x17;
    }
    packet->m_body[1] = 0x01;
    packet->m_body[2] = 0x00;
    packet->m_body[3] = 0x00;
    packet->m_body[4] = 0x00;

    //长度
    packet->m_body[5] = (len >> 24) & 0xff;
    packet->m_body[6] = (len >> 16) & 0xff;
    packet->m_body[7] = (len >> 8) & 0xff;
    packet->m_body[8] = (len) & 0xff;

    //数据
    memcpy(&packet->m_body[9], buf, len);

    packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
    packet->m_nBodySize = body_size;
    //随意分配一个管道（尽量避开rtmp.c中使用的）
    packet->m_nChannel = 0x04;
    // 不使用绝对时间
    packet->m_hasAbsTimestamp = 0;
    packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
    packet->m_nInfoField2 = live->rtmp->m_stream_id;
    return packet;
}

int RtmpHelper::sendPacket(RTMPPacket *packet) {
    // 时间戳
    packet->m_nTimeStamp = RTMP_GetTime() - start_time;
    int ret = RTMP_SendPacket(live->rtmp, packet, 1);
    RTMPPacket_Free(packet);
    free(packet);
    return ret;
}

void RtmpHelper::disconnect() {
    RTMP_Close(live->rtmp);
    RTMP_Free(live->rtmp);

    delete (live->rtmp);
    live->rtmp = nullptr;

    delete (live);
    live = nullptr;
}



